package saobei

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/pkg/xhttp"
	"github.com/go-pay/util"
	"github.com/go-pay/xlog"
)

// 订单分账（旧版）

// doAllocatePost 发起请求
func (c *Client) doAllocatePost(ctx context.Context, path string, bm gopay.BodyMap) (bs []byte, err error) {

	if v := bm.GetString("inst_no"); v == gopay.NULL {
		bm.Set("inst_no", c.instNo)
	}
	if v := bm.GetString("merchant_no"); v == gopay.NULL {
		bm.Set("merchant_no", c.merchantNo)
	}
	sign := c.getRsaSign(bm, "key", c.key)

	bm.Set("key_sign", sign)

	xlog.Debugf("saobeiParam:%+v", bm.JsonBody())

	res, bs, err := c.hc.Req(xhttp.TypeJSON).Post(baseUrl + path).SendBodyMap(bm).EndBytes(ctx)
	if err != nil {
		return nil, err
	}
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
	}
	return bs, nil
}

func (c *Client) doAllocateParam(bm gopay.BodyMap) gopay.BodyMap {
	if v := bm.GetString("pay_ver"); v == util.NULL {
		bm.Set("pay_ver", "110")
	}
	if v := bm.GetString("merchant_no"); v == util.NULL {
		bm.Set("merchant_no", c.merchantNo)
	}
	if v := bm.GetString("terminal_id"); v == util.NULL {
		bm.Set("terminal_id", c.terminalId)
	}
	sign := c.getRsaSign(bm, "", "")
	bm.Set("key_sign", sign)
	return bm
}

// GenAllocateRuleList 生成分账规则
func (c *Client) GenAllocateRuleList(arr []AllocateRule) string {
	var list []AllocateRuleList
	for i, v := range arr {
		list = append(list, AllocateRuleList{
			RuleNo: fmt.Sprintf("%04d", i+1),
			Rules: []AllocateRule{
				v,
			},
		})
	}
	b, _ := json.Marshal(&list)
	return string(b)
}

// GenerateContract 分账规则电子协议生成 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node2
func (c *Client) GenerateContract(ctx context.Context, bm gopay.BodyMap) (rsp *GenerateContractRsp, err error) {
	err = bm.CheckEmptyError("pay_ver", "trace_no", "rule_list_json", "start_date", "end_date")
	if err != nil {
		return nil, err
	}
	var bs []byte
	if bs, err = c.doAllocatePost(ctx, generateContractPath, bm); err != nil {
		return nil, err
	}
	rsp = new(GenerateContractRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, nil
}

// SignContract 分账规则电子协议签署 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node3
func (c *Client) SignContract(ctx context.Context, bm gopay.BodyMap) (rsp *SignContractRsp, err error) {
	err = bm.CheckEmptyError("contract_no")
	if err != nil {
		return nil, err
	}
	var bs []byte
	if bs, err = c.doAllocatePost(ctx, signContractPath, bm); err != nil {
		return nil, err
	}
	rsp = new(SignContractRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, nil
}

// QueryContract 分账电子协议查询 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node4
func (c *Client) QueryContract(ctx context.Context, bm gopay.BodyMap) (rsp *QueryContractRsp, err error) {
	err = bm.CheckEmptyError("contract_no")
	if err != nil {
		return nil, err
	}
	var bs []byte
	if bs, err = c.doAllocatePost(ctx, queryContractPath, bm); err != nil {
		return nil, err
	}
	rsp = new(QueryContractRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, nil
}

// DoAllocate 订单分账 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node5
func (c *Client) DoAllocate(ctx context.Context, bm gopay.BodyMap) (rsp *DoAllocateRsp, err error) {
	err = bm.CheckEmptyError("terminal_trace", "terminal_time", "out_trade_no", "rule_list_json")
	if err != nil {
		return nil, err
	}
	var bs []byte
	bm = c.doAllocateParam(bm)
	if bs, err = c.postBase(ctx, baseUrl, doAllocatePath, bm); err != nil {
		return nil, err
	}
	rsp = new(DoAllocateRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, c.verifySign(bs)
}

// QueryAllocate 分账交易查询 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node6
func (c *Client) QueryAllocate(ctx context.Context, bm gopay.BodyMap) (rsp *QueryAllocateRsp, err error) {
	err = bm.CheckEmptyError("terminal_trace", "terminal_time", "out_trade_no")
	if err != nil {
		return nil, err
	}
	bm = c.doAllocateParam(bm)
	var bs []byte
	if bs, err = c.postBase(ctx, baseUrl, queryAllocatePath, bm); err != nil {
		return nil, err
	}
	rsp = new(QueryAllocateRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err = json.Unmarshal([]byte(rsp.DataListJson), &rsp.DataList); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(rsp.DataListJson))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, c.verifySign(bs)
}

// QueryAllocateTotal 入帐户资金汇总查询 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node7
func (c *Client) QueryAllocateTotal(ctx context.Context, bm gopay.BodyMap) (rsp *QueryAllocateTotalRsp, err error) {
	err = bm.CheckEmptyError("trace_no", "merchant_no", "account_in", "start_date", "end_date")
	if err != nil {
		return nil, err
	}
	var bs []byte
	if bs, err = c.doAllocatePost(ctx, queryAllocateTotalPath, bm); err != nil {
		return nil, err
	}
	rsp = new(QueryAllocateTotalRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err = json.Unmarshal([]byte(rsp.DataListJson), &rsp.DataList); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}

	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, c.verifySign(bs, true)
}

// CancelAllocate 撤销分账 https://help.lcsw.cn/xrmpic/tisnldchblgxohfl/rnqeem#title-node8
func (c *Client) CancelAllocate(ctx context.Context, bm gopay.BodyMap) (rsp *CancelAllocateRsp, err error) {
	err = bm.CheckEmptyError("terminal_trace", "terminal_time", "out_trade_no")
	if err != nil {
		return nil, err
	}
	bm = c.doAllocateParam(bm)
	var bs []byte
	if bs, err = c.postBase(ctx, baseUrl, cancelAllocatePath, bm); err != nil {
		return nil, err
	}
	rsp = new(CancelAllocateRsp)
	if err = json.Unmarshal(bs, rsp); err != nil {
		return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
	}
	if err := bizErrCheck(rsp.RspBase); err != nil {
		return nil, err
	}
	return rsp, c.verifySign(bs)
}
